﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace Neoit.Utils.Extensions
{
    /// <summary>
    /// IEnumerable、List扩展
    /// </summary>
    public static class ListExtension
    {
        #region List至少有一个元素
        /// <summary>
        /// List不为null且至少有一个元素        
        /// </summary>
        public static bool Has<T>(this IEnumerable<T> list)
        {
            return list != null && list.Any();
        }
        #endregion

        #region EmptyIfNull List、T[]
        /// <summary>
        /// 若为null，设为Empty
        /// </summary>
        public static IEnumerable<T> EmptyIfNull<T>(this IEnumerable<T> t)
        {
            if (t == null) return Enumerable.Empty<T>();
            return t;
        }
        #endregion

        #region IEnumerable<T>.WhereIF()方法
        /// <summary>
        /// IEnumerable.WhereIF()
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <param name="condition"></param>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public static IEnumerable<T> WhereIf<T>(this IEnumerable<T> list, bool condition, Func<T, bool> predicate)
        {
            return condition ? list.Where(predicate) : list;
        }
        #endregion

        #region IEnumerable<T>.Page()分页
        /// <summary>
        /// IEnumerable.Page()分页
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <returns></returns>
        public static IEnumerable<T> Page<T>(this IEnumerable<T> list, int pageIndex, int pageSize)
        {
            var res = list.Skip((pageIndex - 1) * pageSize).Take(pageSize);
            return res;
        }
        #endregion

        #region 复制相邻项【重复项相邻】
        /// <summary>
        /// 复制相邻项 {1,2,3} RepeatList(1)  > {1,1,2,2,3,3}
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <param name="repeatCount"></param>
        /// <returns></returns>
        public static IEnumerable<T> RepeatAdjacent<T>(this IEnumerable<T> t, int repeatCount = 1)
        {
            foreach (var item in t)
            {
                for (int i = 0; i < repeatCount + 1; i++)
                {
                    yield return item;
                }
            }
        }
        #endregion

        #region List指定长度分组
        /// <summary>
        /// 指定长度分组{1,2,3,4,5,6} GroupByLength(2) >  [{1,2}{3,4}{5,6}]
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        public static List<List<T>> GroupByLength<T>(this List<T> t, int length)
        {
            if (length < 1) length = 1;
            var listG = new List<List<T>>();
            var TotalLength = t.Count;
            for (int i = 0; i < TotalLength; i += length)
            {
                var trueLength = length;
                if (i + length > TotalLength) trueLength = TotalLength - i;
                listG.Add(t.GetRange(i, trueLength));
            }
            return listG;
        }
        #endregion

        #region 集合拼接字符串
        /// <summary>
        /// 集合拼接字符串
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <param name="separator"></param>
        /// <returns></returns>
        public static string JoinString<T>(this IEnumerable<T> t, string separator = "")
        {
            if (t == null || !t.Any()) return null;
            return string.Join(separator, t);
        }
        #endregion

        #region Flatten
        /// <summary>
        /// Flatten
        /// </summary>
        public static IEnumerable<T> Flatten<T>(this IEnumerable<IEnumerable<T>> source)
        {
            var res = Enumerable.Empty<T>();
            if (source == null) return res;
            return source.Where(s => s != null).SelectMany(item => item);
        }
        #endregion

        #region DistinctX 对象根据属性去重
        /// <summary>
        /// 对象集合根据属性去重
        /// </summary>
        public static IEnumerable<TSource> DistinctX<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
        {
            return source.GroupBy(keySelector).Select(item => item.First()).ToList();
        }
        #endregion

        #region Pivot
        /// <summary>
        /// Pivot，eg：var result5 = l.Pivot(emp => emp.Department, emp2 => emp2.Function, lst => lst.Sum(emp => emp.Salary));
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <typeparam name="TKey1"></typeparam>
        /// <typeparam name="TKey2"></typeparam>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="source"></param>
        /// <param name="key1Selector"></param>
        /// <param name="key2Selector"></param>
        /// <param name="aggregate"></param>
        /// <returns></returns>
        public static Dictionary<TKey1, Dictionary<TKey2, TValue>> Pivot<TSource, TKey1, TKey2, TValue>(this IEnumerable<TSource> source, Func<TSource, TKey1> key1Selector, Func<TSource, TKey2> key2Selector, Func<IEnumerable<TSource>, TValue> aggregate)
        {
            return source.GroupBy(key1Selector).Select(
                x => new
                {
                    X = x.Key,
                    Y = source.GroupBy(key2Selector).Select(
                        z => new
                        {
                            Z = z.Key,
                            V = aggregate(from item in source
                                          where key1Selector(item).Equals(x.Key)
                                          && key2Selector(item).Equals(z.Key)
                                          select item
                            )

                        }
                    ).ToDictionary(e => e.Z, o => o.V)
                }
            ).ToDictionary(e => e.X, o => o.Y);
        }
        #endregion

        #region 指定排序
        /// <summary>
        /// 指定数组排序
        /// </summary>
        public static void SortByOrder<T, TKey>(this List<T> list, Func<T, TKey> keySelector, TKey[] sortOrder)
        {
            list.Sort((p1, p2) =>
            {
                TKey key1 = keySelector(p1);
                TKey key2 = keySelector(p2);
                int index1 = Array.IndexOf(sortOrder, key1);
                int index2 = Array.IndexOf(sortOrder, key2);
                return index1.CompareTo(index2);
            });
        }
        /// <summary>
        /// 指定数组排序
        /// </summary>
        public static void SortByOrder<T, TKey1, TKey2>(this List<T> list, Func<T, TKey1> keySelector1, TKey1[] sortOrder1, Func<T, TKey2> keySelector2, TKey2[] sortOrder2)
        {
            list.Sort((p1, p2) =>
            {
                TKey1 key1 = keySelector1(p1);
                TKey1 key2 = keySelector1(p2);
                int index1 = Array.IndexOf(sortOrder1, key1);
                int index2 = Array.IndexOf(sortOrder1, key2);
                int result = index1.CompareTo(index2);

                if (result != 0)
                {
                    return result;
                }

                TKey2 key3 = keySelector2(p1);
                TKey2 key4 = keySelector2(p2);
                int index3 = Array.IndexOf(sortOrder2, key3);
                int index4 = Array.IndexOf(sortOrder2, key4);
                return index3.CompareTo(index4);
            });
        }
        #endregion

        #region Next Item
        /// <summary>
        /// 获取下个元素
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public static T Next<T>(this IEnumerable<T> list, T item)
        {
            var _list = list.ToList();
            var index = _list.IndexOf(item);
            if (index < 0 || index == _list.Count - 1) return default;

            return _list[index + 1];
        }
        /// <summary>
        /// 获取下个元素
        /// </summary>
        public static T Next<T>(this IEnumerable<T> list, Predicate<T> match)
        {
            var _list = list.ToList();
            var index = _list.FindIndex(match);

            if (index < 0 || index == _list.Count - 1) return default;

            return _list[index + 1];
        }
        #endregion

        #region 相邻项去重
        /// <summary>
        /// 相邻项去重: {"AB","AB","DD","AB"} --> {"AB","DD","AB"}
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <returns></returns>
        public static IEnumerable<T> DistinctAdjacent<T>(this IEnumerable<T> source)
        {
            if (source == null) return default;
            var newList = new List<T>();
            for (int i = 0; i < source.Count(); i++)
            {
                if (i == 0 || (source.ElementAt(i - 1).ToJson() != source.ElementAt(i).ToJson()))
                {
                    newList.Add(source.ElementAt(i));
                }
            }
            return newList;
        }
        #endregion

        #region 二维集合pivot
        /// <summary>
        /// 二维集合pivot
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <returns></returns>
        public static IEnumerable<IEnumerable<T>> Pivot<T>(this IEnumerable<IEnumerable<T>> source)
        {
            if (source == null) return default;
            var pivotedData = Enumerable.Range(0, source.ElementAt(0).Count())
            .Select(columnIndex => source.Select(row => row.ElementAt(columnIndex)));
            return pivotedData;
        }
        #endregion

        /// <summary>
        /// ForEach with index
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <param name="action"></param>
        public static void ForEach<T>(this IEnumerable<T> source, Action<int, T> action)
        {
            int index = 0;
            foreach (var item in source)
            {
                action(index++, item);
            }
        }

    }

    /// <summary>
    /// 比较选项
    /// </summary>
    public enum ComparerOptions
    {
        /// <summary>
        /// 默认相等
        /// </summary>
        Equal = 0,
        /// <summary>
        /// 忽略大小写
        /// </summary>
        IgnoreCase = 1,
    }

}
